import {unsafeStringify} from './stringify'
import {parse} from './parse'

function stringToBytes(str: string): Array<number> {
	str = unescape(encodeURIComponent(str)) // UTF8 escape

	const bytes: number[] = []

	for (let i = 0; i < str.length; ++i) {
		bytes.push(str.charCodeAt(i))
	}

	return bytes
}

export const DNS = '6ba7b810-9dad-11d1-80b4-00c04fd430c8'
export const URL = '6ba7b811-9dad-11d1-80b4-00c04fd430c8'

export function v35(name: string, version: number, hashFunc: Function) {
	function generateUUID(value: string | number[], namespace?: string | Uint8Array, buf?: Uint8Array, offset?: number) {
		if (typeof value === 'string') {
			value = stringToBytes(value)
		}

		if (typeof namespace === 'string') {
			namespace = parse(namespace)
		}

		if (namespace?.length !== 16) {
			throw TypeError('Namespace must be array-like (16 iterable integer values, 0-255)')
		}

		// Compute hash of namespace and value, Per 4.3
		// Future: Use spread syntax when supported on all platforms, e.g. `bytes =
		// hashFunc([...namespace, ... value])`
		let bytes = new Uint8Array(16 + value.length)
		bytes.set(namespace)
		bytes.set(value, namespace.length)
		bytes = hashFunc(bytes)

		bytes[6] = (bytes[6] & 0x0f) | version
		bytes[8] = (bytes[8] & 0x3f) | 0x80

		if (buf) {
			offset = offset || 0

			for (let i = 0; i < 16; ++i) {
				buf[offset + i] = bytes[i]
			}

			return buf
		}

		return unsafeStringify(bytes)
	}

	// Function#name is not settable on some platforms (#270)
	try {
		// @ts-ignore
		generateUUID.name = name
	} catch (err) {
	}

	generateUUID.DNS = DNS
	generateUUID.URL = URL

	return generateUUID
}
